package com.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.constant.IndentStatusConstant;
import com.constant.PosConstant;
import com.domain.entity.*;
import com.domain.req.AddIndentReq;
import com.domain.req.IndentUpdateReq;
import com.domain.req.ListIndentReq;
import com.domain.req.PageReq;
import com.exception.ServiceException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mapper.*;
import com.service.GoodsService;
import com.service.IndentService;
import com.utils.JWTUtils;
import com.utils.ValidatorUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author caishenao
 * @description 针对表【indent】的数据库操作Service实现
 * @createDate 2023-10-12 20:12:39
 */
@Service
@Slf4j
public class IndentServiceImpl implements IndentService {

    @Autowired
    private GoodsService goodsService;

    @Resource
    private GoodsMapper goodsMapper;
    @Resource
    private IndentMapper indentMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private AddressMapper addressMapper;
    @Resource
    private BillMapper billMapper;

    /**
     * 支付订单
     *
     * @param indentId 订单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void payIndent(Integer indentId) {
        log.info("支付订单，请求入参:{}", JSONObject.toJSONString(indentId));
        // 1. 根据id和当前用户查询订单数据
        User currentUser = JWTUtils.getCurrentUser();
        Indent indent = indentMapper.getByIdAndUserId(indentId, currentUser.getId());
        if (indent == null) {
            log.error("id为：{}的订单数据不存在!", JSONObject.toJSONString(indentId));
            throw new ServiceException("订单数据不存在或被删除!");
        }

        // 2. 判断商品信息是否存在
        Goods goods = goodsMapper.getById(indent.getGoodsId());
        if (goods == null) {
            log.error("账单信息:{}中的商品信息不存在!", JSONObject.toJSONString(indent));
            throw new ServiceException("商品信息已不存在!");
        }

        // 3. 根据用户id查询最新的用户数据
        User user = userMapper.getById(currentUser.getId());

        // 4. 判断余额是否充足
        Double money = indent.getMoney();
        BigDecimal balance = user.getBalance();
        BigDecimal moneyDecimal = new BigDecimal(money);
        if (balance.compareTo(moneyDecimal) < 0) {
            log.error("余额不足请即时充值!");
            throw new ServiceException("余额不足请即时充值!");
        }

        // 5. 修改订单状态
        Indent update = new Indent();
        update.setId(indent.getId());
        update.setStatus(IndentStatusConstant.TO_BE_SHIPPED);
        update.setPayTime(new Date());
        indentMapper.updateIndent(update);

        // 6. 新增账单数据
        Bill bill = new Bill();
        bill.setIndentId(indent.getId());
        bill.setUserId(indent.getUserId());
        bill.setTitle(user.getName() + "-" + goods.getName() + "-支付账单");
        bill.setSum(moneyDecimal);
        BigDecimal userBalance = user.getBalance().subtract(moneyDecimal);
        bill.setBalance(userBalance);
        bill.setCreateTime(new Date());
        billMapper.insert(bill);

        // 7. 修改用户余额
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setBalance(userBalance);
        userMapper.updateBySelect(updateUser);
    }

    /**
     * 根据订单id修改订单数据
     *
     * @param indentUpdateReq 订单修改请求
     */
    @Override
    public void updateById(IndentUpdateReq indentUpdateReq) {
        log.info("根据订单id修改订单数据，请求入参:{}", JSONObject.toJSONString(indentUpdateReq));
        // 1. 数据校验
        ValidatorUtils.validateEntity(indentUpdateReq);

        // 2. 查询订单信息
        Indent indent = indentMapper.getById(indentUpdateReq.getId());
        if (indent == null) {
            log.error("订单数据不存在!");
            throw new ServiceException("订单数据不存在!");
        }

        // 3. 判断状态是否可以修改
        if (!IndentStatusConstant.TO_BE_SHIPPED.equals(indent.getStatus())) {
            log.error("订单状态不允许修改!");
            throw new ServiceException("订单状态不允许修改！");
        }

        // 4. 转换为对应的实体
        Indent update = new Indent();
        update.setId(indentUpdateReq.getId());
        update.setNum(indentUpdateReq.getNum());
        update.setMoney(indentUpdateReq.getMoney());

        indentMapper.updateIndent(update);
        log.info("订单信息修改成功!");
    }

    /**
     * 修改订单状态 代发货
     *
     * @param id 订单id
     */
    @Override
    public void shipments(Integer id) {
        log.info("修改订单状态!入参:{}", JSONObject.toJSONString(id));
        // 1. 查询订单数据
        Indent indent = indentMapper.getById(id);
        if (indent == null) {
            log.error("id：{}订单数据为空", JSONObject.toJSONString(id));
            throw new ServiceException("订单数据为空!");
        }

        // 2. 判断订单状态是否允许修改
        if (!IndentStatusConstant.TO_BE_SHIPPED.equals(indent.getStatus())) {
            // 非代发货的状态，不允许修改
            log.error("订单状态无法修改！");
            throw new ServiceException("订单状态无法修改!");
        }

        Indent update = new Indent();
        update.setId(id);
        update.setStatus(IndentStatusConstant.TO_BE_RECEIVED);
        update.setShippingTime(new Date());
        update.setUpdateTime(new Date());
        // 3. 修改订单状态
        indentMapper.updateIndent(update);
    }

    /**
     * 根据订单id收货
     *
     * @param id 订单id
     */
    @Override
    public void receipt(Integer id) {
        log.info("订单收货，入参请求:{}", JSONObject.toJSONString(id));
        // 1. 查询并判断订单信息
        Indent indent = indentMapper.getById(id);
        if (indent == null) {
            log.error("id为{}的订单数据不存在!", JSONObject.toJSONString(id));
            throw new ServiceException("订单数据不存在!");
        }

        // 2. 判断订单的状态
        if (!IndentStatusConstant.TO_BE_RECEIVED.equals(indent.getStatus())) {
            log.error("订单状态不允许收货!数据为:{}", JSONObject.toJSONString(indent));
            throw new ServiceException("订单状态无法收货！");
        }

        // 3. 拼装订单实体，更新数据库
        Indent update = new Indent();
        update.setId(id);
        update.setStatus(IndentStatusConstant.RECEIVED);
        update.setCompleteTime(new Date());
        update.setUpdateTime(new Date());
        indentMapper.updateIndent(update);
    }


    /**
     * 根据订单id查询订单信息
     *
     * @param id 订单id
     * @return 订单信息
     */
    @Override
    public Indent getById(Integer id) {
        log.info("根据订单id查询订单信息，请求入参:{}", JSONObject.toJSONString(id));
        // 1. 查询订单信息
        Indent indent = indentMapper.getById(id);
        if (indent == null) {
            log.error("id：{}对应的订单信息不存在!", JSONObject.toJSONString(id));
            throw new ServiceException("订单信息不存在!");
        }

        // 2. 补充用户信息
        User user = userMapper.getById(indent.getUserId());
        indent.setUser(user);

        // 3. 补充地址信息
        Address address = addressMapper.getById(indent.getAddressId(), indent.getUserId());
        indent.setAddress(address);

        // 4. 补充商品信息
        Goods goods = goodsMapper.getById(indent.getGoodsId());
        indent.setGoods(goods);

        return indent;
    }

    /**
     * 根据账单id删除订单数据
     *
     * @param id 订单id
     */
    @Override
    public void deleteById(Integer id) {
        log.info("根据账单id删除订单数据，请求入参:{}", JSONObject.toJSONString(id));
        // 1. 查询订单数据
        Indent indent = indentMapper.getById(id);
        if (indent == null) {
            log.error("id为:{}的订单数据不存在!", JSONObject.toJSONString(id));
            throw new ServiceException("订单数据不存在!");
        }

        // 2. 判断订单的状态,只能删除待支付的订单
        if (!IndentStatusConstant.TO_BE_PAID.equals(indent.getStatus())) {
            log.error("非待支付状态的订单无法删除！");
            throw new ServiceException("非待支付状态的订单无法删除!");
        }

        // 3. 删除订单信息
        indentMapper.deleteById(indent.getId());

        // 4. 修改商品的库存信息
        Integer goodsId = indent.getGoodsId();
        Goods goods = goodsMapper.getById(goodsId);
        if (goods == null) {
            log.warn("订单:{}关联的商品信息已经不存在了!", JSONObject.toJSONString(indent));
            return;
        }
        goods.setStock(goods.getStock() + indent.getNum());
        goodsMapper.updateGoods(goods);
        log.info("根据账单id删除订单数据处理结束!");
    }

    /**
     * 新增订单
     *
     * @param addIndentReq 新增请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Indent addIndent(AddIndentReq addIndentReq) {
        // 1. 注解校验
        log.info("新增订单入参请求:{}", JSONObject.toJSONString(addIndentReq));
        ValidatorUtils.validateEntity(addIndentReq);

        // 2. 判断货物是否存在
        Goods goods = goodsMapper.getById(addIndentReq.getGoodsId());
        if (goods == null) {
            log.error("id为:{}的商品信息不存在!", JSONObject.toJSONString(addIndentReq.getGoodsId()));
            throw new ServiceException("商品信息不存在!");
        }

        // 3. 判断库存是否充足
        if (goods.getStock() < addIndentReq.getNum()) {
            log.error("库存不足!商品信息:{}", JSONObject.toJSONString(goods));
            throw new ServiceException("库存不足!");
        }

        // 4. 计算订单金额
        Double money = goods.getPrice() * addIndentReq.getNum();

        // 5. 转换对象
        Indent indent = addIndentReqConversion(addIndentReq, money);

        // 6. 新增订单数据
        indentMapper.insert(indent);

        // 6. 扣减库存
        goods.setStock(goods.getStock() - addIndentReq.getNum());
        goodsMapper.updateGoods(goods);
        log.info("新增订单请求处理结束");

        return indent;
    }

    /**
     * 列表查询当前登录用户的所有订单信息
     *
     * @param pageReq       分页请求
     * @param listIndentReq 筛选条件
     * @return 订单信息
     */
    @Override
    public PageInfo<Indent> list(PageReq pageReq, ListIndentReq listIndentReq) {
        log.info("查询订单列表信息");

        // 1. 获取当前登录用户
        User currentUser = JWTUtils.getCurrentUser();
        if (!PosConstant.ADMIN.equals(currentUser.getPos())) {
            // 非管理员只能查询本人订单信息
            listIndentReq.setUserId(currentUser.getId());
        }

        // 2. 开始分页，并查询基础数据
        PageHelper.startPage(pageReq.getPageNum(), pageReq.getPageSize());
        List<Indent> list = indentMapper.list(listIndentReq);

        // 3. 补充相关数据
        for (Indent indent : list) {
            // 补充用户信息
            User user = userMapper.getById(indent.getUserId());
            indent.setUser(user);

            // 补充地址信息
            Address address = addressMapper.getById(indent.getAddressId(), indent.getUserId());
            indent.setAddress(address);

            // 补充商品信息
            Goods goods = goodsMapper.getById(indent.getGoodsId());
            indent.setGoods(goods);

        }

        PageInfo<Indent> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }


    /**
     * 将新增订单请求转换为订单实体
     *
     * @param addIndentReq 新增订单请求
     * @param money        订单金额
     * @return 订单请求
     */
    private Indent addIndentReqConversion(AddIndentReq addIndentReq, Double money) {
        // 1. 获取当前登录用户
        User currentUser = JWTUtils.getCurrentUser();
        Indent indent = new Indent();
        indent.setUserId(currentUser.getId());
        indent.setAddressId(addIndentReq.getAddressId());
        indent.setGoodsId(addIndentReq.getGoodsId());
        indent.setNum(addIndentReq.getNum());
        indent.setMoney(money);
        indent.setStatus(IndentStatusConstant.TO_BE_PAID);
        indent.setCreateTime(new Date());
        return indent;
    }
}




